package com.hulk.rpc.config.server;

import com.google.common.base.Preconditions;
import com.hulk.rpc.annotation.HulkService;
import com.hulk.rpc.config.common.ConfigException;
import com.hulk.rpc.config.common.HostPort;
import com.hulk.rpc.serialize.Serializer;
import com.hulk.rpc.serialize.impl.json.JacksonMapper;
import com.hulk.rpc.serialize.impl.json.JsonMapper;
import com.typesafe.config.Config;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.hulk.rpc.config.common.ConfigUtils.getStringOrElse;

/**
 * @author xuxukang
 * @date 2019-03-10 20:00
 */
@Data
@Accessors(chain = true)
@NoArgsConstructor
public class ServerConfig {

  private String group;
  private String app;
  private String ownerName;
  private String ownerPhone;
  private Serializer serializer = Serializer.SerializeEnum.proto.getSerializer();
  private JsonMapper jsonMapper = new JacksonMapper();
  private List<RegistryConfig> registryConfigs;

  public ServerConfig(String group, String app) {
    this.group = group;
    this.app = app;
  }

  public static ServerConfig parse(Config config) {
    Preconditions.checkNotNull(config);

    String group = getStringOrElse(config, "group", HulkService.default_group);
    String app = getStringOrElse(config, "app", HulkService.default_app);
    String name = getStringOrElse(config, "owner.name", "");
    String phone = getStringOrElse(config, "owner.phone", "");

    String serializerName = getStringOrElse(config, "serializer.type", Serializer.SerializeEnum.proto.name());
    Serializer serializer = Serializer.SerializeEnum.valueOf(serializerName).getSerializer();

    List<? extends Config> registerConfigList = config.getConfigList("registers");
    List<RegistryConfig> registryConfigs = RegistryConfig.parseList(registerConfigList);
    Map<Integer, RegistryConfig> portMap = new HashMap<>();
    for (RegistryConfig registryConfig : registryConfigs) {
      HostPort serverAddress = registryConfig.getServerAddress();
      RegistryConfig existed = portMap.get(serverAddress.getPort());

      if (existed == null) {
        portMap.put(serverAddress.getPort(), registryConfig);
        continue;
      }

      if (existed.getProtocolType() == registryConfig.getProtocolType()
              && existed.getServerAddress().equals(serverAddress)) {
        continue;
      }

      throw new ConfigException("存在端口冲突: " + registryConfig + " vs " + existed);
    }

    return new ServerConfig().setApp(app)
            .setGroup(group)
            .setOwnerName(name)
            .setOwnerPhone(phone)
            .setRegistryConfigs(registryConfigs);
  }

}
